package com.yinxing.quartz.api;

import com.yinxing.framework.exception.YinXingException;
import com.yinxing.quartz.job.HelloJob;
import com.yinxing.webapi.code.viewobje.sys.QuartzJobsVo;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PostMapping;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

@Slf4j
@Service
public class QuartzService {

    @Autowired
    private Scheduler scheduler;

    /**
     * 查询引擎中全部任务列表
     */
    public List<QuartzJobsVo> getAllJobs() {
        List<QuartzJobsVo> quartzJobsVOList = new ArrayList<>();
        try {
            List<String> triggerGroupNames = scheduler.getTriggerGroupNames();
            for (String groupName : triggerGroupNames) {
                GroupMatcher groupMatcher = GroupMatcher.groupEquals(groupName);
                Set<TriggerKey> triggerKeySet = scheduler.getTriggerKeys(groupMatcher);
                for (TriggerKey triggerKey : triggerKeySet) {
                    CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
                    JobKey jobKey = trigger.getJobKey();
                    JobDetail job =  scheduler.getJobDetail(jobKey);

                    QuartzJobsVo vo = new QuartzJobsVo();
                    vo.setJobName(jobKey.getName());
                    vo.setJobGroupName(jobKey.getGroup());
                    vo.setJobDescription(job.getDescription());
                    vo.setJobClassName( job.getJobClass().getSimpleName());

                    vo.setTriggerName(triggerKey.getName());
                    vo.setTriggerGroupName(triggerKey.getGroup());
                    vo.setCronExpression(trigger.getCronExpression());
                    vo.setTriggerState(scheduler.getTriggerState(triggerKey).name());
                    vo.setStartTime(trigger.getStartTime());
                    vo.setNextFireTime(trigger.getNextFireTime());
                    vo.setPreviousFireTime(trigger.getPreviousFireTime());
                    quartzJobsVOList.add(vo);
                }
            }
        } catch (Exception e) {
            log.error("获取任务信息错误", e);
            throw new YinXingException("获取任务信息错误");
        }

        return quartzJobsVOList;
    }

    /**
     * 添加任务
     * @param jobName 任务名称
     * @param jobDescription 任务说明
     * @param cronExpression 执行周期表达式
     */
    public void addJob(String jobName, String jobDescription, String cronExpression) {
        try {
            JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                    .withIdentity(jobName)
                    .storeDurably()
                    .withDescription(jobDescription)
                    .build();
            Trigger trigger = TriggerBuilder.newTrigger()
                    .forJob(jobDetail)
                    .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
                    .build();
            scheduler.scheduleJob(jobDetail, trigger);
        } catch (SchedulerException e) {
            log.error("添加任务失败", e);
            throw new YinXingException("添加任务失败");
        }
    }

    /**
     * 暂停任务
     * @param jobName 任务名称
     * @param jobGroupName 任务组名称
     */
    public void pauseJob(String jobName, String jobGroupName) {
        try {
            JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
            scheduler.pauseJob(jobKey);
        } catch (SchedulerException e) {
            log.error("暂停任务失败", e);
            throw new YinXingException("暂停任务失败");
        }
    }

    /**
     * 恢复任务
     * @param jobName 任务名称
     * @param jobGroupName 任务组名称
     */
    public void resumeJob(String jobName, String jobGroupName) {
        try {
            JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
            scheduler.resumeJob(jobKey);
        } catch (SchedulerException e) {
            log.error("恢复任务失败", e);
            throw new YinXingException("恢复任务失败");
        }
    }

    /**
     * 删除任务
     * @param jobName 任务名称
     * @param jobGroupName 任务组名称
     */
    public void deleteJob(String jobName, String jobGroupName) {
        try {
            JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
            scheduler.deleteJob(jobKey);
        } catch (SchedulerException e) {
            log.error("删除任务失败", e);
            throw new YinXingException("删除任务失败");
        }
    }

    /**
     * 立即运行任务
     * @param jobName 任务名称
     * @param jobGroupName 任务组名称
     */
    public void triggerJob(String jobName, String jobGroupName) {
        try {
            JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
            scheduler.triggerJob(jobKey);
        } catch (SchedulerException e) {
            log.error("运行任务失败", e);
            throw new YinXingException("运行任务失败");
        }
    }

    /**
     * 更新时间表达式
     * @param triggerName 触发器名称
     * @param triggerGroupName 触发器组名称
     */
    @PostMapping("/rescheduleJob")
    public void rescheduleJob(String triggerName, String triggerGroupName, String cronExpression) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(triggerName,triggerGroupName);
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            if(trigger == null) {
                throw new YinXingException("查询不到触发器");
            }
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
                    .withSchedule(scheduleBuilder).build();
            scheduler.rescheduleJob(triggerKey, trigger);
        } catch (SchedulerException e) {
            log.error("更新时间表达式失败", e);
            throw new YinXingException("更新时间表达式失败");
        }
    }
}
